package com.piggy.settlement.sdk.util;

import cn.hutool.core.util.StrUtil;
import com.piggy.settlement.sdk.annotation.PiggySig;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map.Entry;
import java.util.TreeMap;

/**
 * @author ：daxia
 * @description：计算签名的工具类
 * @modified By：
 * @version: 1.0$
 */
public class PiggyVerifyUtil {


    /**
     * 签名生成算法
     *
     * @param params<String,String> params 请求参数集，所有参数必须已转换为字符串类型
     * @param secret                secret 签名密钥
     * @param params
     * @return 签名
     * @throws IOException
     */
    public static String getSigStr(String secret, Object params) throws Exception {

        //获取map转换为String 字符串
        String paramsString = buildMapToSign(params);
        //获取密文串
        String baseString = secret + paramsString;

        byte[] bytes = null;
        // 使用MD5对待签名串求签
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            bytes = md5.digest(baseString.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            System.out.println("签名计算md5出错:" + e.getMessage());
            return null;
        } catch (UnsupportedEncodingException e) {
            System.out.println("签名计算encode出错:" + e.getMessage());
            return null;
        }

        // 将MD5输出的二进制结果转换为小写的十六进制
        StringBuilder sign = new StringBuilder();
        if (bytes != null) {
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(bytes[i] & 0xFF);
                if (hex.length() == 1) {
                    sign.append("0");
                }
                sign.append(hex);
            }
        }
        String sigReturn = sign.toString();
        return sigReturn;
    }

    /**
     * 1、先将 paramMap 进行key排序, 如果是多值参数, 例如type=b&type=a, 将参数值进行正序排序
     * 2、然后将排序后的 Map 转换为用&及=拼接的字符串
     *
     * @return String like "name1=a&name2=b
     */
    public static String buildMapToSign(Object params) throws UnsupportedEncodingException, IllegalAccessException {


        TreeMap<String, Object> sortMap = new TreeMap<>();

        Class clz = params.getClass();
        Field[] fields = clz.getDeclaredFields();
        PiggySig annotation = null;
        for (Field field : fields) {
            annotation = field.getAnnotation(PiggySig.class);
            if (null != annotation && annotation.value() == true) {
                field.setAccessible(true);
                if (null != field.get(params) && !StrUtil.hasBlank(field.get(params).toString())) {
                    sortMap.put(field.getName(), field.get(params));
                }
            }
        }

        StringBuilder builder = new StringBuilder();

        for (Entry<String, Object> e : sortMap.entrySet()) {

            String key = e.getKey();
            String values = "";
            if (null != e.getValue()) {
                values = e.getValue().toString();
            }
            if (StrUtil.hasBlank(values)) {
                continue;
            }
            if (StrUtil.hasBlank(builder)) {
                builder.append(String.format("%s=%s", key, URLEncoder.encode(values, "UTF-8")));
            } else {
                builder.append(String.format("&%s=%s", key, URLEncoder.encode(values, "UTF-8")));
            }
        }
        return builder.toString();
    }

}
